package br.ufg.inf.espweb.sgca.service.impl;

import br.ufg.inf.espweb.sgca.dao.GenericDao;
import br.ufg.inf.espweb.sgca.dao.UsuarioDao;
import br.ufg.inf.espweb.sgca.model.Discente;
import br.ufg.inf.espweb.sgca.model.Docente;
import br.ufg.inf.espweb.sgca.model.Pessoa;
import br.ufg.inf.espweb.sgca.model.TipoDeDocente;
import br.ufg.inf.espweb.sgca.model.Usuario;
import br.ufg.inf.espweb.sgca.service.UsuarioService;
import br.ufg.inf.espweb.sgca.service.exception.AutenticationException;
import br.ufg.inf.espweb.sgca.service.ldap.LDAPParametrosConfig;
import br.ufg.inf.espweb.sgca.service.ldap.LDAPServiceLocator;
import br.ufg.inf.espweb.sgca.util.SegurancaUtils;
import java.net.SocketException;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.SearchResult;
import org.joda.time.LocalDateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

/**
 *
 * @author diCastro
 */
@Service
@Scope("prototype")
@Transactional(propagation = Propagation.REQUIRED)
public class UsuarioServiceImpl extends GenericServiceImpl<Usuario> implements UsuarioService{
    
    @Autowired
    private UsuarioDao usuarioDao;
    
    @Override
    public Usuario encontrar(String username, String password) throws AutenticationException {
        Usuario usuario = null;
        String nomeCompleto ="uid=" + username + ", ou=Users,dc=dionisio, dc=inf, dc=ufg, dc=br";
        //String login = "amanda";
        //String senha = "Aed5ahm4";
        
        try{
            DirContext ctx = LDAPServiceLocator.getInstance().getContext(nomeCompleto, password);
            usuario = usuarioDao.buscarUsuarioPorUserName(username);
            if(usuario == null){
                Attributes matchAttrs = new BasicAttributes(false);
                matchAttrs.put("uid", username);
                // Array de atributos que deseja retornar do LDAP
                String[] atributosRetorno = new String[]{"mail", "cn", "uid", "uidNumber", "gidNumber"};
                
                // Parametros de busca
                //matchAttrs.put(new BasicAttribute("uid", login));
                //matchAttrs.put(new BasicAttribute("userPassword", senha));
                
                // Efetua a busca
                NamingEnumeration resultado = ctx.search(LDAPParametrosConfig.SEARCHBASE, matchAttrs, atributosRetorno);
                
                usuario = new Usuario();
                Pessoa pessoa = null;
                String nome = null;
                String email = null;
                while (resultado.hasMore()) {
                    SearchResult sr = (SearchResult) resultado.next();
                    
                    Attributes atributos = sr.getAttributes();
                    for (NamingEnumeration todosAtributos = atributos.getAll(); todosAtributos.hasMore();) {
                        Attribute attrib = (Attribute) todosAtributos.next();
                        switch(attrib.getID()){
                            case "mail":
                                email = (String) attrib.get();
                                break;
                                
                            case "uid":
                                usuario.setUsername((String) attrib.get());
                                break;
                                
                            case "cn":
                                nome = (String) attrib.get();
                                break;
                                
                            case "gidNumber":
                                if(((String)attrib.get()).equals("500")){
                                    pessoa = new Discente();
                                }else if(((String)attrib.get()).equals("101")){
                                    pessoa = new Docente(TipoDeDocente.PROFESSOR);
                                }else{
                                    pessoa = new Docente(TipoDeDocente.FUNCIONARIO);
                                }
                                break;
                            default:
                                break;
                        }
                    }
                }
                pessoa.setEmail(email);
                pessoa.setNome(nome.split(" ")[0]);
                pessoa.setNomeCompleto(nome);
                usuario.setPessoa(pessoa);
                usuario.setUltimoLogin(LocalDateTime.now());
                usuario.setSenha(SegurancaUtils.encriptografar(password));
                usuarioDao.salvar(usuario);
            }else{
                usuario.setUltimoLogin(LocalDateTime.now());
                usuario.setSenha(SegurancaUtils.encriptografar(password));
                usuarioDao.atualizar(usuario);
            }
        } catch(NamingException e) {
            if(e.getCause() instanceof SocketException){
                usuario = usuarioDao.buscarUsuarioPorUserName(username);
                if(usuario == null || usuario.getSenha() == null){
                    throw new AutenticationException("Falha ao comunicar com o servidor de autenticação.");
                }else if(usuario != null && usuario.getSenha() != null && !usuario.getSenha().equals(SegurancaUtils.encriptografar(password))){
                    throw new AutenticationException("Servidor de autenticação offline. Entre com a senha usada pela última vez nesse sistema.");
                }
            }else{
                throw new AutenticationException(e.getLocalizedMessage(), e);
            }
        }
        
        return usuario;
    }
    
    @Override
    protected GenericDao<Usuario> getDao() {
        return usuarioDao;
    }

    @Override
    public void importarUsuariosDoLDAP() {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }
}
